from datetime import datetime

from flask import g
from flask_restful import Resource, abort, marshal
from sqlalchemy import desc, and_, or_

from app.api.admin.parsers import get_param_parser
from app.api.wxapp.fields import goods_fields, goods_list_fields, order_fields, order_list_fields, branch_fields, \
    explain_fields
from app.api.wxapp.fields import banner_fields
from app.api.wxapp.parsers import pagination_parser, sort_parser, filter_parser, add_order_args, branch_filter_parser
from app.exception import APIException, GOODS_NOT_EXISTS, GOODS_NOT_LISTING, GOODS_NOT_ONLINE, ADDRESS_IS_REQUIRED, \
    BRANCH_IS_REQUIRED, DOLL_NOT_ENOUGH, DATABASE_ERROR
from app.extensions import auth, db
from app.models import Banner, Goods, Order, UserAddress, UserRecord, Branch, Explain
from app.utils import generate_order_no


class BannersResource(Resource):
    methods = ['GET', 'OPTIONS']
    # decorators = [auth.login_required]

    def get(self):
        args = get_param_parser.parse_args()

        # 未删除 按权重 创建时间排序
        query = Banner.query.filter_by(deleted=0).order_by(Banner.created.desc()).order_by(Banner.weights.desc())

        page_args = pagination_parser.parse_args(req=args)
        page = page_args.get('page')
        per_page = page_args.get('per_page')

        _banners = query.paginate(page, per_page=per_page, error_out=False)
        # _banners = query.all()
        banners = {
            'list': marshal(_banners.items, banner_fields),
            'pageSize': _banners.per_page,
            'pageNo': _banners.page,
            'pages': _banners.pages,
            'total': _banners.total
        }

        return {
           'code': 0,
           'message': '',
           'data': banners
        }, 200


class BranchesResource(Resource):
    methods = ['GET', 'OPTIONS']
    decorators = [auth.login_required]

    def get(self):
        args = get_param_parser.parse_args()

        query = Branch.query

        _filter = args.get('filter')
        if _filter:
            filter_args = branch_filter_parser.parse_args(req=args)
            keyword = filter_args.pop('keyword')
            if keyword:
                query = query.filter(
                    or_(Branch.name.like("%" + keyword + "%"), Branch.address.like("%" + keyword + "%")))
            else:
                for k, v in filter_args.items():
                    if v is not None:
                        query = query.filter(getattr(Branch, k).like("%" + v + "%"))

        page_args = pagination_parser.parse_args(req=args)
        page = page_args.get('page')
        per_page = page_args.get('per_page')

        _branchs = query.paginate(page, per_page=per_page, error_out=False)

        branchs = {
            'list': marshal(_branchs.items, branch_fields),
            "pageSize": _branchs.per_page,
            "pageNo": _branchs.page,
            "totalPage": _branchs.pages,
            "totalCount": _branchs.total
        }

        return {
           'code': 0,
           'message': '',
           'data': branchs
        }, 200


class GoodsResource(Resource):
    methods = ['OPTIONS', 'GET']
    # decorators = [auth.login_required]

    @staticmethod
    def goods_exist(goods_id):
        goods = Goods.query.get(goods_id)
        if not goods:
            # abort(404, message='商品(id=%s)不存在' % goods_id, code=404)
            raise APIException(GOODS_NOT_EXISTS)
        return goods

    def get(self, goods_id):
        goods = self.goods_exist(goods_id)
        return {
           'code': 0,
           'message': '',
           'data': marshal(goods, goods_fields)
        }, 200


class GoodsListResource(Resource):
    methods = ['GET', 'OPTIONS']
    # decorators = [auth.login_required]

    def get(self):
        args = get_param_parser.parse_args()

        query = Goods.query.filter(and_(Goods.deleted == 0, Goods.is_listing == 1)).order_by(Goods.updated.desc())

        _filter = args.get('filter')
        if _filter:
            filter_args = filter_parser.parse_args(req=args)
            name = filter_args.pop('name')
            if name:
                query = query.filter(Goods.name.like("%" + name + "%"))
            category_id = filter_args.pop('category_id')
            if category_id:
                query = query.filter_by(category_id=category_id)
            recommended = filter_args.pop('recommended')
            if recommended == 1:
                query = query.filter_by(recommended=recommended)

        _sort = args.get('sort')
        if _sort:
            sort_args = sort_parser.parse_args(req=args)
            field = getattr(Goods, sort_args.get('field'))
            if sort_args.get('reverse'):
                field = desc(field)
            query = query.order_by(field)

        page_args = pagination_parser.parse_args(req=args)
        page = page_args.get('page')
        per_page = page_args.get('per_page')

        _goods = query.paginate(page, per_page=per_page, error_out=False)

        goods = {
            'list': marshal(_goods.items, goods_list_fields),
            "pageSize": _goods.per_page,
            "pageNo": _goods.page,
            "pages": _goods.pages,
            "total": _goods.total
        }

        return {
           'code': 0,
           'message': '',
           'data': goods
        }, 200


class OrderResource(Resource):
    methods = ['OPTIONS', 'GET']
    decorators = [auth.login_required]

    @staticmethod
    def order_exist(order_id):
        order = Order.query.get(order_id)
        if not order:
            # abort(404, message='商品(id=%s)不存在' % order_id, code=404)
            raise APIException(GOODS_NOT_EXISTS)
        return order

    def get(self, order_id):
        order = self.order_exist(order_id)
        return {
           'code': 0,
           'message': '',
           'data': marshal(order, order_fields)
        }, 200


class OrderListResource(Resource):
    methods = ['GET', 'OPTIONS', 'POST']
    decorators = [auth.login_required]

    def get(self):
        args = get_param_parser.parse_args()
        user = g.user
        query = Order.query.filter_by(user_id=user.id).order_by(Order.created.desc())

        page_args = pagination_parser.parse_args(req=args)
        page = page_args.get('page')
        per_page = page_args.get('per_page')

        _orders = query.paginate(page, per_page=per_page, error_out=False)

        orders = {
            'list': marshal(_orders.items, order_list_fields),
            "pageSize": _orders.per_page,
            "pageNo": _orders.page,
            "pages": _orders.pages,
            "total": _orders.total
        }

        return {
           'code': 0,
           'message': '',
           'data': orders
        }, 200

    def post(self):
        args = add_order_args.parse_args()
        goods_id = args.get('goods_id')
        goods = Goods.query.get(goods_id)
        if not goods or goods.deleted:
            raise APIException(GOODS_NOT_EXISTS)
        elif goods.is_listing == 0:
            raise APIException(GOODS_NOT_LISTING)
        user = g.user
        #  创建订单
        exchange_type = args.get('exchange_type')

        if exchange_type == 0:  # 线下兑换
            branch_id = args.get('branch_id')
            if not branch_id:
                raise APIException(BRANCH_IS_REQUIRED)
            address_id = 0
        elif exchange_type == 1:  # 线上兑换
            if goods.is_online == 0:
                raise APIException(GOODS_NOT_ONLINE)

            address_row = args.get('address')
            if not address_row:
                raise APIException(ADDRESS_IS_REQUIRED)
            branch_id = user.branch_id
            address_row['user_id'] = user.id
            address = UserAddress.create(False, **address_row)
            address_id = address.id

        if user.doll < goods.exchange_price:
            raise APIException(DOLL_NOT_ENOUGH)

        order_no = generate_order_no(user.id)
        row = {
            'order_no': order_no,
            'goods_id': goods_id,
            'user_id': user.id,
            'branch_id': branch_id,
            'order_time': datetime.now(),
            'exchange_type': exchange_type,
            'status': exchange_type,
            'amount': goods.exchange_price,
            'address_id': address_id,
            'remark': ''
        }
        order = Order.create(False, **row)
        # 更新用户娃娃
        user.doll = user.doll - goods.exchange_price
        user.update(False,)
        # 插入用户娃娃变更记录
        record_row = {
            'user_id': user.id,
            'type': 2 if exchange_type == 1 else 3,
            'doll': -goods.exchange_price
        }
        UserRecord.create(False, **record_row)
        # 更新商品的兑换个数
        goods.exchange_num += 1
        goods.update(False,)

        try:
            db.session.commit()
        except Exception as e:
            db.session.rollback()
            raise APIException(DATABASE_ERROR)
        return {
           'code': 0,
           'message': '创建成功',
           'data': {}
        }, 201


class ExplainResource(Resource):
    methods = ['GET', 'OPTIONS']
    # decorators = [auth.login_required]

    def get(self):
        args = get_param_parser.parse_args()

        # 未删除 按创建时间排序
        query = Explain.query.filter().order_by(Explain.created.desc())

        page_args = pagination_parser.parse_args(req=args)
        page = page_args.get('page')
        per_page = page_args.get('per_page')

        _explain = query.paginate(page, per_page=per_page, error_out=False)

        explain = {
            'list': marshal(_explain.items, explain_fields),
            'pageSize': _explain.per_page,
            'pageNo': _explain.page,
            'pages': _explain.pages,
            'total': _explain.total
        }

        return {
           'code': 0,
           'message': '',
           'data': explain
        }, 200